package vip.aster.generator.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import vip.aster.common.exception.BusinessException;
import vip.aster.generator.config.template.GeneratorConfig;
import vip.aster.generator.config.template.GeneratorInfo;
import vip.aster.generator.config.template.TemplateInfo;
import vip.aster.generator.entity.GenBaseClass;
import vip.aster.generator.entity.GenTable;
import vip.aster.generator.entity.GenTableField;
import vip.aster.generator.service.*;
import vip.aster.generator.utils.TemplateUtils;
import vip.aster.generator.vo.PreviewVO;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * GeneratorServiceImpl
 *
 * @author Aster
 * @since 2024/2/26 11:55
 */
@Service
@Slf4j
@AllArgsConstructor
public class GeneratorServiceImpl implements GeneratorService {
    private final GenDataSourceService datasourceService;
    private final GenFieldTypeService fieldTypeService;
    private final GeneratorConfig generatorConfig;
    private final GenTableService tableService;
    private final GenTableFieldService tableFieldService;
    private final GenBaseClassService baseClassService;

    @Override
    public void downloadCode(String tableId, ZipOutputStream zip) {
        // 数据模型
        Map<String, Object> dataModel = getDataModel(tableId);

        // 代码生成器信息
        GeneratorInfo generator = generatorConfig.getGeneratorConfig();

        // 渲染模板并输出
        for (TemplateInfo template : generator.getTemplates()) {
            String templateName = template.getTemplateName();
            Object baseClass = dataModel.get("baseClass");
            if (templateName.contains("BaseEntity.java.ftl") && baseClass == null) {
                continue;
            }
            dataModel.put("templateName", templateName);
            String content = TemplateUtils.getContent(template.getTemplateContent(), dataModel);
            String path = TemplateUtils.getContent(template.getGeneratorPath(), dataModel);
            path = TemplateUtils.getPath(path);

            try {
                // 添加到zip
                zip.putNextEntry(new ZipEntry(path));
                IoUtil.writeUtf8(zip, false, content);
                zip.flush();
                zip.closeEntry();
            } catch (IOException e) {
                throw new BusinessException("模板写入失败：" + path, e);
            }
        }
    }

    @Override
    public void generatorCode(String tableId) {
        // 数据模型
        Map<String, Object> dataModel = getDataModel(tableId);

        // 代码生成器信息
        GeneratorInfo generator = generatorConfig.getGeneratorConfig();

        // 渲染模板并输出
        for (TemplateInfo template : generator.getTemplates()) {
            String templateName = template.getTemplateName();
            Object baseClass = dataModel.get("baseClass");
            if (templateName.contains("BaseEntity.java.ftl") && baseClass == null) {
                continue;
            }
            dataModel.put("templateName", template.getTemplateName());
            String content = TemplateUtils.getContent(template.getTemplateContent(), dataModel);
            String path = TemplateUtils.getContent(template.getGeneratorPath(), dataModel);

            FileUtil.writeUtf8String(content, path);
        }
    }

    @Override
    public List<PreviewVO> preview(String tableId) {
        Map<String, Object> dataModel = getDataModel(tableId);
        // 代码生成器信息
        GeneratorInfo generator = generatorConfig.getGeneratorConfig();
        return generator.getTemplates().stream().map(t -> {
            dataModel.put("templateName", t.getTemplateName());
            String content = TemplateUtils.getContent(t.getTemplateContent(), dataModel);
            String fileName = t.getGeneratorPath().substring(t.getGeneratorPath().lastIndexOf("/") + 1);
            fileName = TemplateUtils.getContent(fileName, dataModel);
            return new PreviewVO(fileName, content);
        }).collect(Collectors.toList());
    }

    /**
     * 获取渲染的数据模型
     *
     * @param tableId 表ID
     */
    private Map<String, Object> getDataModel(String tableId) {
        // 表信息
        GenTable table = tableService.getById(tableId);
        List<GenTableField> fieldList = tableFieldService.getByTableId(tableId);
        table.setFieldList(fieldList);

        // 数据模型
        Map<String, Object> dataModel = new HashMap<>();

        // 获取数据库类型
        String dbType = datasourceService.getDatabaseProductName(table.getDatasourceId());
        dataModel.put("dbType", dbType);

        // 项目信息
        dataModel.put("package", table.getPackageName());
        dataModel.put("packagePath", table.getPackageName().replace(".", File.separator));
        dataModel.put("version", table.getVersion());
        dataModel.put("moduleName", table.getModuleName());
        dataModel.put("ModuleName", StrUtil.upperFirst(table.getModuleName()));
        dataModel.put("moduleSimple", table.getModuleSimple());
        dataModel.put("functionName", table.getFunctionName());
        dataModel.put("FunctionName", StrUtil.upperFirst(table.getFunctionName()));
        dataModel.put("formLayout", table.getFormLayout());

        // 开发者信息
        dataModel.put("author", table.getAuthor());
        dataModel.put("email", table.getEmail());
        dataModel.put("datetime", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN));
        dataModel.put("date", DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN));

        DefaultIdentifierGenerator identifierGenerator = DefaultIdentifierGenerator.getInstance();

        // sql信息
        dataModel.put("menuId", identifierGenerator.nextId(new Object()).toString());
        dataModel.put("searchId", identifierGenerator.nextId(new Object()).toString());
        dataModel.put("infoId", identifierGenerator.nextId(new Object()).toString());
        dataModel.put("addId", identifierGenerator.nextId(new Object()).toString());
        dataModel.put("editId", identifierGenerator.nextId(new Object()).toString());
        dataModel.put("deleteId", identifierGenerator.nextId(new Object()).toString());

        // 设置字段分类
        setFieldTypeList(dataModel, table);

        // 设置基类信息
        GenBaseClass baseClass = setBaseClass(dataModel, table);

        // 导入的包列表
        Set<String> importList = fieldTypeService.getPackageByTableId(table.getId());
        dataModel.put("importList", importList);

        // 表信息
        dataModel.put("tableName", table.getTableName());
        dataModel.put("tableComment", table.getTableComment());
        dataModel.put("className", StrUtil.lowerFirst(table.getClassName()));
        dataModel.put("ClassName", table.getClassName());
        dataModel.put("fieldList", table.getFieldList());

        // 表中是否有LocalDateTime类型的字段
        long count = fieldList.stream().filter(f -> "LocalDateTime".equals(f.getAttrType())
                && (baseClass != null && !baseClass.getFields().contains(f.getFieldName()))).count();

        dataModel.put("hasDate", count > 0);

        // 生成路径
        dataModel.put("backendPath", table.getBackendPath());
        dataModel.put("frontendPath", table.getFrontendPath());

        return dataModel;
    }

    /**
     * 设置基类信息
     *
     * @param dataModel 数据模型
     * @param table     表
     */
    private GenBaseClass setBaseClass(Map<String, Object> dataModel, GenTable table) {
        if (StrUtil.isBlank(table.getBaseClassId())) {
            return null;
        }
        GenBaseClass baseClass = baseClassService.getById(table.getBaseClassId());

        dataModel.put("baseClass", baseClass);

        // 基类字段
        String[] fields = baseClass.getFields().split(",");

        // 标注为基类字段
        for (GenTableField field : table.getFieldList()) {
            if (ArrayUtil.contains(fields, field.getFieldName())) {
                field.setBaseField(true);
            }
        }
        return baseClass;
    }

    /**
     * 设置字段分类信息
     *
     * @param dataModel 数据模型
     * @param table     表
     */
    private void setFieldTypeList(Map<String, Object> dataModel, GenTable table) {
        // 主键列表 (支持多主键)
        List<GenTableField> primaryList = new ArrayList<>();
        // 表单列表
        List<GenTableField> formList = new ArrayList<>();
        // 网格列表
        List<GenTableField> gridList = new ArrayList<>();
        // 查询列表
        List<GenTableField> queryList = new ArrayList<>();

        for (GenTableField field : table.getFieldList()) {
            if (field.isPrimaryPk()) {
                primaryList.add(field);
            }
            if (field.isFormItem()) {
                formList.add(field);
            }
            if (field.isGridItem()) {
                gridList.add(field);
            }
            if (field.isQueryItem()) {
                queryList.add(field);
            }
        }
        dataModel.put("primaryList", primaryList);
        dataModel.put("formList", formList);
        dataModel.put("gridList", gridList);
        dataModel.put("queryList", queryList);
    }
}
